#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pygtk
pygtk.require('2.0')

import gtk
import gtk.gtkgl

import gobject

from OpenGL.GL import *
from OpenGL.GLU import *

import galaxy_vis
import main
import proc

from gtkcodebuffer import CodeBuffer, SyntaxLoader, add_syntax_path
import sys, os
import time

add_syntax_path("./")

import multiprocessing
import pynwheel

class gtk_launcher(object, pynwheel.pynwheel):
    def __init__(self, galaxyvis):
        self.toolkit = "gtk"
        self.galaxyvis = galaxyvis

        self.display_mode = gtk.gdkgl.MODE_RGB    | \
                            gtk.gdkgl.MODE_DEPTH  | \
                            gtk.gdkgl.MODE_DOUBLE

        # Try to create a double buffered framebuffer,
        # if not successful then try to create a single
        # buffered one.
        try:
            self.glconfig = gtk.gdkgl.Config(mode=self.display_mode)
        except gtk.gdkgl.NoMatches:
            self.display_mode &= ~gtk.gdkgl.MODE_DOUBLE
            self.glconfig = gtk.gdkgl.Config(mode=self.display_mode)


        # Create the window for the app.
        self.win = gtk.Window()
        self.win.set_default_size(800, 600)
        self.win.set_title('pynwheel')
        if sys.platform != 'win32':
            self.win.set_resize_mode(gtk.RESIZE_IMMEDIATE)
        self.win.set_reallocate_redraws(True)
        self.win.connect('destroy', lambda quit: gtk.main_quit())
        self.win.connect('key_press_event', self.__key_press_event)

        hpane = gtk.HPaned()
        self.win.add(hpane)
        hpane.show()

        self.vbox = gtk.VBox()
        hpane.pack1(self.vbox, False, False)
        self.vbox.show()
        
        # DrawingArea for OpenGL rendering.
        self.glarea = gtk.gtkgl.DrawingArea(self.glconfig)
        self.glarea.set_size_request(400, 400)
        # connect to the relevant signals.
        self.glarea.connect_after('realize', self.__realize)
        self.glarea.connect('configure_event', self.__configure_event)
        self.glarea.connect('expose_event', self.__expose_event)
        self.glarea.connect('map_event', self.smap)

        self.glarea.set_events (gtk.gdk.EXPOSURE_MASK
                               | gtk.gdk.LEAVE_NOTIFY_MASK
                               | gtk.gdk.BUTTON_PRESS_MASK
                               | gtk.gdk.POINTER_MOTION_MASK
                               | gtk.gdk.POINTER_MOTION_HINT_MASK);
        self.glarea.connect('motion_notify_event', self.__motion_event)
        self.glarea.show()

        # code editor
        lang = SyntaxLoader("python")
        self.buff = CodeBuffer(lang=lang)
        comment = "# star_list: [{\"x\", \"y\", \"z\", \"class\", \"temperature\", \"sid\"}]\n"
        comment+= "# planet_list: [{\"r\", \"mval\", \"mexp\", \"distance\", \"i\", \"vo\", \"vo\", \"a\", \"ve\", \"sid\"}]\n"
        comment+= "# moon_list: [{\"r\", \"mval\", \"mexp\", \"distance\", \"i\", \"vo\", \"vo\", \"a\", \"ve\", \"pid\"}]\n"
        comment+= "# insert star_list members or star_list slices in\n"
        comment+= "# highlight list to mark them\n"
        comment+= "data = {\"stars\": star_list, \"planets\": planet_list, \"moons\": moon_list}\n"
#        comment+= "import sys\n"
#        comment+= "sys.path.append(\"../pynwheel_submitted/v\")\n"

        self.buff.set_text(comment)

        self.scr = gtk.ScrolledWindow()
        self.code = gtk.TextView(self.buff)
        self.scr.add(self.code)
        self.scr.show()

        vpane = gtk.VPaned()
        self.vbox.pack_start(vpane)
        vpane.pack1(self.glarea, False, False)
        vpane.pack2(self.scr, True, False)
        vpane.show()


        # A quit button.
        self.button = gtk.Button('Execute')
        self.button.connect('clicked', self.eval_it)
        self.vbox.pack_start(self.button, expand=False)
        self.button.show()

        self.disp_scr = gtk.ScrolledWindow()
        self.disp = gtk.TextView()
        self.disp.set_wrap_mode(gtk.WRAP_WORD)
        self.disp_scr.add(self.disp)
        self.disp.set_property("editable", False)

        hpane.pack2(self.disp_scr, True, False)
        self.disp_scr.show()

    def hide_widgets(self, really=True):
        if not really:
            self.button.show()
            self.disp_scr.show()
            self.disp.show()
            self.scr.show()
            self.code.show()
            return
        self.button.hide()
        self.disp_scr.hide()
        self.disp.hide()
        self.scr.hide()
        self.code.hide()

    def __key_press_event(self, widget, event):
        if event.keyval == gtk.keysyms.F5:
            if not self.fullscreen:
                self.win.fullscreen()
                self.fullscreen = True
                self.hide_widgets()
            else:
                self.win.unfullscreen()
                self.fullscreen = False
                self.hide_widgets(False)

    def __motion_event(self, glarea, event):
        if event.state & gtk.gdk.BUTTON1_MASK:
            pointer = self.win.get_pointer()
            self.galaxyvis.motionFunc(pointer[0], pointer[1])

    def smap(self, glarea, event):
        gobject.idle_add(self.idle, glarea)
        return True

    def __realize(self, widget):
        gldrawable = widget.get_gl_drawable()
        glcontext = widget.get_gl_context()

        # OpenGL begin.
        if not gldrawable.gl_begin(glcontext):
            return

        self.galaxyvis.initGL()

        gldrawable.gl_end()
        # OpenGL end
    
    def __configure_event(self, widget, event):
        gldrawable = widget.get_gl_drawable()
        glcontext = widget.get_gl_context()

        width = widget.allocation.width
        height = widget.allocation.height

        # OpenGL begin.
        if not gldrawable.gl_begin(glcontext):
            return
        
        self.galaxyvis.resizeGLScene(width, height)

        gldrawable.gl_end()
        # OpenGL end

    def __expose_event(self, widget, event):
        gldrawable = widget.get_gl_drawable()
        glcontext = widget.get_gl_context()

        height = widget.allocation.height

        if not gldrawable.gl_begin(glcontext):
            return

        self.galaxyvis.drawGLScene()

        if gldrawable.is_double_buffered():
            gldrawable.swap_buffers()
        else:
            glFlush()

        gldrawable.gl_end()

    def idle (self, glarea):
        self.check_data()
        time.sleep(0.01)
        # Invalidate whole window.
        glarea.window.invalidate_rect(glarea.allocation, False)
        # Update window synchronously (fast).
        glarea.window.process_updates(False)
        return True
    
    def run(self):
        self.win.show_all()
        gtk.main()

def start(data, perf):
    gv = galaxy_vis.galaxyvis(400, 400, data, perf)
    app = gtk_launcher(gv)
    app.run()
